/*
 * AGENT SHERPA
 *  
 * Assignement 2 of the Agent Oriented Software Engineering Course
 * M.Sc. in Advanced Software Engineering (Part-time)
 * University College Dublin www.ucd.ie
 *
 * Copyright (c) 2007 Chris Walsh, Aidan Morrisy and Iain Hull.
 * All rights reserved.
 */

package org.agentsherpa;

import java.util.HashMap;
import java.util.Map;

import org.agentsherpa.model.CellType;
import org.agentsherpa.model.Direction;
import org.agentsherpa.model.Point;


/**
 * The LocationPerceptor provides agent beliefs, for its current location It
 * interfaces with the LocationModule to provide this data.
 */
public class LocationPerceptor extends BasePerceptor {
    /**
     * percieve the current state of the known map.
     * 
     * This is only an example of possible beliefs.
     */
    public void perceive() {
        try {
            SimulatorService simulator = getSimulator();
            Point location = simulator.getLocation(this.agent);
            Point targetLocation = simulator.getTargetLocation();
            adoptBelief("BELIEF(location" + location + ")");
            
            LocationModule locationModule = getLocationModule();
            Map<Point, CellType> senses = locationModule.sense();
            
            //adoptToTheBeliefs(location, senses, targetLocation);
            adoptPreferedDirectionBelief(location, senses, targetLocation);
        }
        catch(PerceptorException e) {
            e.printStackTrace();
        }
    }

    /**
     * Find the prefered direction.
     * @param location
     * @param senses
     * @param targetLocation
     */
    private void adoptPreferedDirectionBelief(Point location, Map<Point, CellType> senses, Point targetLocation) {
    	Map<Direction, Point> bestDirections = new HashMap<Direction, Point>();
    	int topScore = 0;
    	
    	for(Direction dir : Direction.values()) {
    		Point p = dir.move(location);
    		
    		CellType cell = senses.get(p);
    		if (cell == null) {
    			continue;
    		}
    		
            adoptBelief("BELIEF(toThe("+dir+","+cell+"))");
    		
//    		System.out.print("Score " + dir + "\t");
    		int score = calculateCellScore(p, senses);
    		
    		if (score > topScore) {
    			topScore = score;
    			bestDirections.clear();
    			bestDirections.put(dir, p);
    		}
    		else if (score == topScore) {
    			bestDirections.put(dir, p);
    		}
    	}
		if (!bestDirections.isEmpty()) {	
			adoptBelief("BELIEF(wantToMove("+selectBest(bestDirections, targetLocation)+"))");
		}
	}

    private Direction selectBest(Map<Direction, Point> directions, Point targetLocation) {
    	Direction ret = Direction.West;
    	double distance = Double.MAX_VALUE;
    	for (Map.Entry<Direction, Point> e : directions.entrySet()) {
			double d = targetLocation.distance(e.getValue());
			if (d < distance) {
				distance = d;
				ret = e.getKey();
			}    		
    	}
    	return ret;
	}

	/**
     * Calculate the score, for visiting this location.
     * @param location
     * @param senses
     * @return
     */
	private int calculateCellScore(Point location, Map<Point, CellType> senses) {
		CellType currCell = senses.get(location);
		if (currCell == CellType.DRONE) {
			return 0; 	// Cannot move another drone there
		}
		int score = currCell.getScore() * 2;

//		System.out.print(currCell + "\t");
    	for(Direction dir : Direction.values()) {
    		Point p = dir.move(location);
    		CellType cell = senses.get(p);
//    		System.out.print(dir + ": " + cell + "\t");
    		if (cell != null) {
    			score += cell.getScore();
    		}
    	}
//    	System.out.println(score);
		return score;
	}
}